package com.elastic;

import com.elastic.assistant.RunLeader;
import com.elastic.chain.ChooseQuery;
import com.elastic.chain.FinalLeader;
import com.elastic.chain.Leader;
import com.elastic.chain.QueryAdapter;
import com.elastic.exceptions.ESException;
import com.elastic.inis.DefaultBuilder;
import com.elastic.sort.impl.DefaultBuilderType;
import com.elastic.sort.type.DefaultEnumType;
import com.elastic.utils.InfoAndMap;
import com.elastic.utils.PramCheck;
import com.elastic.utils.ESSpringContextUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @ClassName MajorManage
 * @Author xiezhuocai
 * @Description es查询在这里构建
 * @Date 2021/12/22 10:59
 */
public final class ESMajorManage {


    /**
     * @Description 构建查询对象
     */
    private QueryBuilder boolQuery;

    /**
     * @Description 查询对象key和value
     */
    private Map<String, Object> keysAndValues;

    /**
     * @Description repository查询对象
     */
    private ElasticsearchRepository repository;

    /**
     * @Description 分页对象
     */
    private PageRequest pageRequest;

    /**
     * @Description es排序设置
     */
    private SortBuilder<?> sortBuilder;

    /**
     * @Description 字段属性的默认
     */
    private Leader finalLeader;


    /**
     * @Description 字段策略链
     */
    private Leader leader;


    /**
     * @Description 返回的类型
     */
    private Class<?> resultClass;

    /**
     * @Description 类的使用状态
     */
    private boolean status = false;

    /**
     * @Description 匹配字段查询
     */
    private ChooseQuery chooseQuery;


    ESMajorManage(){
        this.boolQuery = QueryBuilders.boolQuery();
    }

    ESMajorManage(QueryBuilder boolQuery){
        this.boolQuery = boolQuery;
    }

    public static ESMajorManage initDefaultESMajorManage(){
        ESMajorManage manage = new ESMajorManage();
        return initObject(manage);
    }

    public static ESMajorManage initDefaultESMajorManage(QueryBuilder boolQuery){
        ESMajorManage manage = new ESMajorManage(boolQuery);
        return initObject(manage);
    }

    private static ESMajorManage initObject(ESMajorManage manage){
        DefaultBuilder defaultBuilder = new DefaultBuilder(manage);
        defaultBuilder.buildChooseQuery();
        defaultBuilder.buildFinalLeader();
        defaultBuilder.buildLeader();
        return defaultBuilder.buildESProduct();
    }

    /**
     * @Description 设置默认排序
     */
    public void toDefaultSort(){
        toSort(0);
    }

    /**
     * @Description 设置排序
     */
    public void toSort(Integer code){
        PramCheck.isNotNull(code);
        //默认排序
        this.sortBuilder =
                new DefaultBuilderType().setSort(Objects.requireNonNull(DefaultEnumType.getByCode(String.valueOf(code))));
    }

    public void toLeader(Leader leader){
        leader.setNext(this.leader.getNext());
        this.leader.setNext(leader);
    }

    public void setChooseQuery(ChooseQuery chooseQuery) {
        this.chooseQuery = chooseQuery;
    }

    public void setLeader(Leader leader) {
        this.leader = leader;
    }


    public void setFinalLeader(FinalLeader finalLeader) {
        this.finalLeader = finalLeader;
    }

    public Leader getFinalLeader() {
        return finalLeader;
    }

    public void setRepository(ElasticsearchRepository repository, Object info){
        this.repository = repository;
        this.keysAndValues = InfoAndMap.getKeysAndValues(info);
    }

    public void setRepository(ElasticsearchRepository repository){
        this.repository = repository;
    }

    public void setInfo(Object info){
        this.keysAndValues = InfoAndMap.getKeysAndValues(info);
        this.resultClass = info.getClass();
    }

    public void setSortBuilder(SortBuilder<?> sortBuilder) {
        this.sortBuilder = sortBuilder;
    }

    public void setPageRequest(PageRequest pageRequest) {
        //PageRequest.of(page - 1, size)
        this.pageRequest = pageRequest;
    }

    //构建DSL查询
    public List<Object> createRepositoryBoolQuery(){
        PramCheck.isNotNull(repository);
        PramCheck.isNotNull(keysAndValues);
        return repository.search(execute()).getContent();
    }

    public NativeSearchQuery execute(){
        //if (this.status) throw new ESException("未清理,重复使用");
        //this.status = true;
        NativeSearchQueryBuilder searchQuery;
        synchronized (this) {
            searchQuery = new NativeSearchQueryBuilder();
            final Leader[] underway = {this.leader};
            keysAndValues.forEach((k, v) -> {
                while (true) {
                    if (underway[0].handleRequest((BoolQueryBuilder)boolQuery,k,v)) {
                        break;
                    } else {
                        underway[0] = underway[0].getNext();
                    }
                }
            });
            if (boolQuery != null) {
                searchQuery.withQuery(boolQuery);
            }
            if (pageRequest != null) {
                searchQuery.withPageable(pageRequest);
            }
            if (sortBuilder != null) {
                searchQuery.withSort(sortBuilder);
            }
        }
        NativeSearchQuery resource = searchQuery.build();
        //this.status = false;
        return resource;
    }

    public List<Object> createBoolQuery(){
        PramCheck.isNotNull(keysAndValues);
        SearchHits<?> search = ESSpringContextUtils.getContext().getBean(ElasticsearchRestTemplate.class).search(execute(),
                this.resultClass);
        List<Object> list = new ArrayList<>();
        for (SearchHit<?> searchHit : search.getSearchHits()) {
            list.add(searchHit.getContent());
        }
        return list;
    }

    /*
     * @Author xiezhuocai
     * @Description //通过字段设置模糊查询,其他查询未实现
     * @Date 2021/12/28 18:13
     * @Param
     * @return
     **/
    public void mustWildcardQuery(String field){
        PramCheck.isNotNull(field);
        Leader leader = chooseQuery.mustWildcardQuery(field);
        toLeader(leader);
    }

}
